home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
gnu
/
ghview15.gz
/
ghostview-1.5.tar
/
ghostview-1.5
/
callbacks.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-07-23
|
20KB
|
713 lines
/*
* callbacks.c -- X11 callbacks for ghostview.
* Copyright (C) 1992 Timothy O. Theisen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Author: Tim Theisen Systems Programmer
* Internet: tim@cs.wisc.edu Department of Computer Sciences
* UUCP: uwvax!tim University of Wisconsin-Madison
* Phone: (608)262-0438 1210 West Dayton Street
* FAX: (608)262-9777 Madison, WI 53706
*/
#include <stdio.h>
#ifndef BUFSIZ
#define BUFSIZ 1024
#endif
#ifdef VMS
#define getenv _getenv
#endif
extern char *getenv();
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Cardinals.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Scrollbar.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Command.h>
#include "Ghostview.h"
#include "gv.h"
#include "ps.h"
/* Start application folding up by Destroying the top level widget. */
/* The application exits when the last interpreter is killed during */
/* a destroy callback from ghostview widgets. */
void
quit_ghostview(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
XtDestroyWidget(toplevel);
}
/* Popup a window. */
void
popup(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
positionpopup((Widget)client_data);
XtPopup((Widget)client_data, XtGrabNone);
XRaiseWindow(XtDisplay((Widget)client_data), XtWindow((Widget)client_data));
}
/* Popup a dialog box. */
void
popup_dialog(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
#ifdef SELFILE
Widget button;
String okay, cancel;
String name, init_path;
Arg args[1];
FILE* fp;
struct stat sbuf;
extern FILE *XsraSelFile();
button = XtNameToWidget(dialog, "cancel");
if (button) {
XtSetArg(args[0], XtNlabel, &cancel);
XtGetValues(button, args, ONE);
}
button = XtNameToWidget(dialog, "okay");
if (button) {
XtSetArg(args[0], XtNlabel, &okay);
XtGetValues(button, args, ONE);
}
#endif
mode = (int) client_data;
switch (mode) {
case PRINT_WHOLE:
case PRINT_MARKED:
SetDialogPrompt(dialog, app_res.print_prompt);
if (app_res.default_printer)
SetDialogResponse(dialog, app_res.default_printer);
else
ClearDialogResponse(dialog);
popup(w, (XtPointer)dialogpopup, call_data);
break;
case OPEN:
#ifdef SELFILE
if (filename && strcmp(filename, "-")) init_path = filename;
else init_path = NULL;
fp = XsraSelFile(toplevel, app_res.open_prompt, okay, cancel,
app_res.open_fail, init_path, "r", NULL, &name);
if (fp == NULL) break;
if (oldfilename) XtFree(oldfilename);
oldfilename = filename;
filename = name;
if (psfile) fclose(psfile);
psfile = fp;
stat(filename, &sbuf);
mtime = sbuf.st_mtime;
new_file(0);
show_page(0);
#else
SetDialogPrompt(dialog, app_res.open_prompt);
if (filename && strcmp(filename, "-"))
SetDialogResponse(dialog, filename);
else
ClearDialogResponse(dialog);
popup(w, dialogpopup, call_data);
#endif
break;
case SAVE:
#ifdef SELFILE
fp = XsraSelFile(toplevel, app_res.save_prompt, okay, cancel,
app_res.save_fail, "", "w", NULL, &name);
if (fp == NULL) break;
pscopydoc(fp);
fclose(fp);
XtFree(name);
#else
SetDialogPrompt(dialog, app_res.save_prompt);
ClearDialogResponse(dialog);
popup(w, dialogpopup, call_data);
#endif
break;
}
}
/* Explicitly reopen the file. */
void
reopen_file(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
struct stat sbuf;
int number = current_page;
fclose(psfile);
psfile = fopen(filename, "r");
mtime = sbuf.st_mtime;
if (oldfilename) XtFree(oldfilename);
oldfilename = XtNewString(filename);
new_file(number);
show_page(number);
}
/* Get the selection, if no selection, get the insertion point. */
/* If the new_page is different from the current page show it. */
/* If not at the first page, show the previous page. */
void
prev_page(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
XawTextPosition pos, end;
int new_page;
XawTextGetSelectionPos(toc, &pos, &end);
if (pos == end) { /* Nothing selected */
pos = XawTextGetInsertionPoint(toc);
}
if ((new_page = pos/toc_entry_length) == current_page) {
new_page = current_page - 1;
}
if (new_page < 0) return;
show_page(new_page);
}
/* Get the selection, if no selection, get the insertion point. */
/* Show this page. */
void
this_page(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
if (toc_text) {
XawTextPosition pos, end;
int new_page;
XawTextGetSelectionPos(toc, &pos, &end);
if (pos == end) { /* Nothing selected */
pos = XawTextGetInsertionPoint(toc);
}
new_page = pos/toc_entry_length;
show_page(new_page);
} else {
GhostviewDisableInterpreter(page);
show_page(0);
}
}
/* Get the selection, if no selection, get the insertion point. */
/* If the new_page is different from the current page show it. */
/* If not at the last page, show the next page. */
void
next_page(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
XawTextPosition pos, end;
int new_page = 0;
if (toc_text) {
XawTextGetSelectionPos(toc, &pos, &end);
if (pos == end) { /* Nothing selected */
pos = XawTextGetInsertionPoint(toc);
}
if ((new_page = pos/toc_entry_length) == current_page) {
new_page = current_page + 1;
}
if (new_page >= doc->numpages) return;
}
show_page(new_page);
}
/* Center the viewport over the page */
void
center_page(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
Arg args[2];
Widget scroll;
float top, shown;
scroll = XtNameToWidget(pageview, "vertical");
if (scroll) {
XtSetArg(args[0], XtNshown, &shown);
XtSetArg(args[1], XtNtopOfThumb, &top);
XtGetValues(scroll, args, TWO);
top = (1.0 - shown) / 2.0;
XtCallCallbacks(scroll, XtNjumpProc, &top);
}
scroll = XtNameToWidget(pageview, "horizontal");
if (scroll) {
XtSetArg(args[0], XtNshown, &shown);
XtSetArg(args[1], XtNtopOfThumb, &top);
XtGetValues(scroll, args, TWO);
top = (1.0 - shown) / 2.0;
XtCallCallbacks(scroll, XtNjumpProc, &top);
}
}
/* Get the selection, if no selection, get the insertion point. */
/* Mark all pages in range, and cause toc to update. */
void
mark_page(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
XawTextPosition begin, end;
int i;
XawTextGetSelectionPos(toc, &begin, &end);
if (begin == end) { /* Nothing selected */
begin = end = XawTextGetInsertionPoint(toc);
} else {
end--; /* Sometimes end spills onto next line */
}
for (i = begin/toc_entry_length; i <= end/toc_entry_length; i++) {
toc_text[i*toc_entry_length] = '*';
XawTextInvalidate(toc, i*toc_entry_length, i*toc_entry_length+1);
}
}
/* Get the selection, if no selection, get the insertion point. */
/* Unmark all pages in range, and cause toc to update. */
void
unmark_page(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
XawTextPosition begin, end;
int i;
XawTextGetSelectionPos(toc, &begin, &end);
if (begin == end) { /* Nothing selected */
begin = end = XawTextGetInsertionPoint(toc);
} else {
end--; /* Sometimes end spills onto next line */
}
for (i = begin/toc_entry_length; i <= end/toc_entry_length; i++) {
toc_text[i*toc_entry_length] = ' ';
XawTextInvalidate(toc, i*toc_entry_length, i*toc_entry_length+1);
}
}
/* Set new magstep. Reshow the current page if magstep changed. */
void
set_magstep(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
app_res.magstep = (int)client_data;
if (set_new_magstep()) {
layout_ghostview();
show_page(current_page);
}
}
/* Set new orientation. Reshow the current page if orientation changed. */
void
set_orientation(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
app_res.force_orientation = force_setting;
app_res.orientation = (XtPageOrientation) client_data;
if (set_new_orientation(current_page)) {
layout_ghostview();
show_page(current_page);
}
}
/* Swap the landscape labels and change the flag. */
void
swap_landscape(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
Arg args[1];
String s1, s2;
app_res.swap_landscape = !app_res.swap_landscape;
XtSetArg(args[0], XtNlabel, &s1);
XtGetValues(landscapebutton, args, ONE);
s1 = XtNewString(s1);
XtSetArg(args[0], XtNlabel, &s2);
XtGetValues(seascapebutton, args, ONE);
s2 = XtNewString(s2);
XtSetArg(args[0], XtNlabel, s2);
XtSetValues(landscapebutton, args, ONE);
XtSetArg(args[0], XtNlabel, s1);
XtSetValues(seascapebutton, args, ONE);
XtFree(s1);
XtFree(s2);
if (set_new_orientation(current_page)) {
layout_ghostview();
show_page(current_page);
}
}
/* Set new page media. If new page media is different, update app_resources */
/* and redisplay page. */
void
set_pagemedia(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
int new_pagemedia = (int) client_data;
if (new_pagemedia >= base_papersize) {
default_pagemedia = new_pagemedia;
app_res.force_pagemedia = force_setting;
} else {
document_media = new_pagemedia;
force_document_media = force_setting;
}
if (set_new_pagemedia(current_page)) {
layout_ghostview();
show_page(current_page);
}
}
/* track mouse pointer and popup zoom window */
void
track_and_zoom(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
Arg args[20];
Cardinal num_args;
Dimension width, height;
Widget zoom;
Widget zoomform;
Widget zoompage;
Widget zoomdismiss;
FILE *zoomfile;
struct stat sbuf;
GhostviewReturnStruct *p = (GhostviewReturnStruct *)call_data;
int llx;
int lly;
int urx;
int ury;
int bottom_margin;
int left_margin;
int right_margin;
int top_margin;
int i;
/* locator events have zero width and height */
if ((p->width == 0) || (p->height == 0)) {
char buf[32];
if (!app_res.show_locator) return;
sprintf(buf, "(%d, %d)", p->psx, p->psy);
XtSetArg(args[0], XtNlabel, buf);
XtSetValues(locator, args, ONE);
return;
}
/* If no file, nothing to zoom. */
if (!psfile) return;
/* If the file changed, cannot zoom */
stat(filename, &sbuf);
if (mtime != sbuf.st_mtime) return;
zoom = XtCreatePopupShell("zoom", topLevelShellWidgetClass,
toplevel, NULL, ZERO);
zoomform = XtCreateManagedWidget("form", formWidgetClass,
zoom, NULL, ZERO);
llx = p->psx - p->width/2;
lly = p->psy - p->height/2;
urx = p->psx + p->width/2;
ury = p->psy + p->height/2;
/* Make sure zoom window doesn't go off the edge of the page */
if (llx < current_llx) {
llx = current_llx;
urx = llx + p->width;
}
if (lly < current_lly) {
lly = current_lly;
ury = lly + p->height;
}
if (urx > current_urx) {
urx = current_urx;
llx = urx - p->width;
}
if (ury > current_ury) {
ury = current_ury;
lly = ury - p->height;
}
if (llx < current_llx) {
llx = current_llx;
}
if (lly < current_lly) {
lly = current_lly;
}
bottom_margin = lly - current_lly;
left_margin = llx - current_llx;
right_margin = current_urx - urx;
top_margin = current_ury - ury;
num_args = 0;
XtSetArg(args[num_args], XtNtop, XtChainTop); num_args++;
XtSetArg(args[num_args], XtNbottom, XtChainBottom); num_args++;
XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
XtSetArg(args[num_args], XtNright, XtChainRight); num_args++;
XtSetArg(args[num_args], XtNorientation, current_orientation);
num_args++;
XtSetArg(args[num_args], XtNllx, llx); num_args++;
XtSetArg(args[num_args], XtNlly, lly); num_args++;
XtSetArg(args[num_args], XtNurx, urx); num_args++;
XtSetArg(args[num_args], XtNury, ury); num_args++;
XtSetArg(args[num_args], XtNbottomMargin, bottom_margin);
num_args++;
XtSetArg(args[num_args], XtNleftMargin, left_margin);
num_args++;
XtSetArg(args[num_args], XtNrightMargin, right_margin);
num_args++;
XtSetArg(args[num_args], XtNtopMargin, top_margin); num_args++;
XtSetArg(args[num_args], XtNbottomMargin, bottom_margin);
num_args++;
XtSetFloatArg(args[num_args], XtNxdpi, p->xdpi); num_args++;
XtSetFloatArg(args[num_args], XtNydpi, p->ydpi); num_args++;
if (!toc_text) {
XtSetArg(args[num_args], XtNfilename, filename); num_args++;
}
zoompage = XtCreateManagedWidget("page", ghostviewWidgetClass,
zoomform, args, num_args);
num_ghosts++;
XtAddCallback(zoompage, XtNcallback, track_and_zoom, (XtPointer)0);
XtAddCallback(zoompage, XtNmessageCallback, message, (XtPointer)zoompage);
XtAddCallback(zoompage, XtNdestroyCallback, destroy_ghost,
(XtPointer)zoompage);
num_args = 0;
XtSetArg(args[num_args], XtNfromVert, zoompage); num_args++;
XtSetArg(args[num_args], XtNtop, XtChainBottom); num_args++;
XtSetArg(args[num_args], XtNbottom, XtChainBottom); num_args++;
XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
XtSetArg(args[num_args], XtNright, XtChainRight); num_args++;
zoomdismiss = XtCreateManagedWidget("dismiss", commandWidgetClass,
zoomform, args, num_args);
XtAddCallback(zoomdismiss, XtNcallback, destroy, (XtPointer)zoom);
XtSetArg(args[0], XtNwidth, &width);
XtGetValues(zoompage, args, ONE);
XtSetArg(args[0], XtNwidth, width);
XtSetValues(zoomdismiss, args, ONE);
XtRealizeWidget(zoom);
positionpopup(zoom);
num_args = 0;
XtSetArg(args[num_args], XtNwidth, &width); num_args++;
XtSetArg(args[num_args], XtNheight, &height); num_args++;
XtGetValues(zoom, args, num_args);
num_args = 0;
XtSetArg(args[num_args], XtNminWidth, width); num_args++;
XtSetArg(args[num_args], XtNminHeight, height); num_args++;
XtSetArg(args[num_args], XtNmaxWidth, width); num_args++;
XtSetArg(args[num_args], XtNmaxHeight, height); num_args++;
XtSetValues(zoom, args, num_args);
XSetWMProtocols(XtDisplay(zoom), XtWindow(zoom), &wm_delete_window, 1);
XtPopup(zoom, XtGrabNone);
if (toc_text) {
zoomfile = fopen(filename, "r");
if (zoomfile == NULL) return;
GhostviewSendPS(zoompage, zoomfile, doc->beginprolog,
doc->lenprolog, False);
GhostviewSendPS(zoompage, zoomfile, doc->beginsetup,
doc->lensetup, False);
if (doc->pageorder == DESCEND)
i = (doc->numpages - 1) - current_page;
else
i = current_page;
GhostviewSendPS(zoompage, zoomfile, doc->pages[i].begin,
doc->pages[i].len, True);
}
}
/* Process messages from ghostscript */
/* Refresh occurs when window was resized unexpectedly */
void
message(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
int i;
char *error;
if (!strcmp((char *) call_data, "Failed")) {
if ((Widget)client_data == page) {
error = "Error: PostScript interpreter failed in main window.\n\n";
} else {
error = "Error: PostScript interpreter failed in zoom window.\n\n";
}
output(w, NULL, error);
} else if (!strcmp((char *) call_data, "BadAlloc")) {
if ((Widget)client_data == page) {
error =
"Warning: Could not allocate backing pixmap in main window.\n\n";
} else {
error =
"Warning: Could not allocate backing pixmap in zoom window.\n\n";
}
output(w, NULL, error);
} else if (!strcmp((char *) call_data, "Refresh")) {
if (toc_text) {
GhostviewSendPS(w, psfile, doc->beginprolog,
doc->lenprolog, False);
GhostviewSendPS(w, psfile, doc->beginsetup,
doc->lensetup, False);
if (doc->pageorder == DESCEND)
i = (doc->numpages - 1) - current_page;
else
i = current_page;
GhostviewSendPS(w, psfile, doc->pages[i].begin,
doc->pages[i].len, False);
}
}
}
/* Take output from ghostscript and display it in the infotext popup window */
void
output(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
Arg args[2];
XawTextBlock message_block;
message_block.firstPos = 0;
message_block.length = strlen(call_data);
message_block.ptr = call_data;
message_block.format = FMT8BIT;
XawTextDisableRedisplay(infotext);
XtSetArg(args[0], XtNeditType, XawtextAppend);
XtSetValues(infotext, args, ONE);
XawTextReplace(infotext, info_length, info_length, &message_block);
info_length = info_length + message_block.length;
XtSetArg(args[0], XtNeditType, XawtextRead);
XtSetArg(args[1], XtNinsertPosition, info_length);
XtSetValues(infotext, args, TWO);
XawTextEnableRedisplay(infotext);
if (!info_up) XtPopup(infopopup, XtGrabNone);
info_up = True;
}
/* Dismiss popup dialog */
void
okay(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
String name, error;
Widget dialog;
dialog = (Widget)client_data;
name = GetDialogResponse(dialog);
switch (mode) {
case PRINT_WHOLE:
case PRINT_MARKED:
if (error = print_file(name, (mode == PRINT_WHOLE))) {
char *buf = XtMalloc(strlen(error) +
strlen(app_res.print_prompt) + 2);
sprintf(buf, "%s\n%s", error, app_res.print_prompt);
SetDialogPrompt(dialog, buf);
XtFree(error);
XtFree(buf);
} else {
XtPopdown(XtParent(dialog));
}
break;
case OPEN:
if (error = open_file(name)) {
char *buf = XtMalloc(strlen(error) +
strlen(app_res.open_prompt) + 2);
sprintf(buf, "%s\n%s", error, app_res.open_prompt);
SetDialogPrompt(dialog, buf);
XtFree(error);
XtFree(buf);
} else {
XtPopdown(XtParent(dialog));
}
break;
case SAVE:
if (error = save_file(name)) {
char *buf = XtMalloc(strlen(error) +
strlen(app_res.save_prompt) + 2);
sprintf(buf, "%s\n%s", error, app_res.save_prompt);
SetDialogPrompt(dialog, buf);
XtFree(error);
XtFree(buf);
} else {
XtPopdown(XtParent(dialog));
}
break;
}
XtFree(name);
}
/* Dismiss popup window */
void
dismiss(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
XtPopdown((Widget)client_data);
if ((Widget)client_data == infopopup) info_up = False;
}
/* Destroy popup window */
void
destroy(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
XtDestroyWidget((Widget)client_data);
}
/* destroy callback for Ghostview widgets. */
/* The disable interpreter call ensures that ghostscript is killed. */
/* One the count goes to 0, we are sure that all forked processes have */
/* been killed and that we can safely exit. */
void
destroy_ghost(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
GhostviewDisableInterpreter((Widget) client_data);
num_ghosts--;
if (num_ghosts) return;
if (dying) old_Xerror(XtDisplay(w), &bomb);
XtDestroyApplicationContext(app_con);
exit(0);
}